import os
import select
import fcntl
import socket,struct,time

tapReadLen = 2000
sockReadLen = 65536
cacheLen = 1024*1024

def openTap(name):
    TUNSETIFF = 0x400454ca
    TUNSETOWNER = TUNSETIFF + 2
    IFF_TUN = 0x0001
    IFF_TAP = 0x0002
    IFF_NO_PI = 0x1000
    tun = open('/dev/net/tun', 'r+b',buffering=0)
    ifr = struct.pack('16sH', name, IFF_TAP | IFF_NO_PI)
    fcntl.ioctl(tun, TUNSETIFF, ifr)
    return tun



def getMsg(d):
    ret = []
    while True:        
        if len(d)<4:
            return d,ret
        l = struct.unpack('I',d[:4])[0]
        if l>len(d)-4:
            return d,ret
        ret.append(d[4:4+l])
        d = d[4+l:]
        
     

def work(s,tap) :  
    staTime = time.monotonic() 
    totalT = lostT = 0
    
    tapBuf = b''
    sockBuf = b''    
    while True:
        if time.monotonic() -staTime>1:
            staTime = time.monotonic() 
            print(totalT,lostT)
            totalT = lostT = 0
        totalT += 1
        w = []
        if tapBuf:
            w = [s]
        r = [s]
        if len(tapBuf)<cacheLen:
            r.append(tap)
        else:
            lostT += 1
        r,w,e = select.select(r,w,[])
        if tap in r:
            st = os.read(tap.fileno(), tapReadLen)
            tapBuf += struct.pack('I',len(st))+st
        if s in r:
            st = s.recv(sockReadLen)
            sockBuf += st
            sockBuf,l = getMsg(sockBuf)
            for i in l:
                os.write(tap.fileno(),i)
        if s in w:
            n = s.send(tapBuf)
            tapBuf = tapBuf[n:]